﻿#region [ Modification History ]
/*
 * 06/04/2013 Denis Kholine
 *  Add comments and license
 */
#endregion

#region  [ UIUC NCSA Open Source License ]
/*****************************************************************************\
 *             University of Illinois/NCSA Open Source License
 *
 * 
 *      Copyright © 2012,2013, The Board of Trustees of the University of Illinois. All rights reserved.
 *
 *      Developed by: Rakesh Bobba, Derek Dagit, Erich Heine, Denis Kholine,
 *                    Klara Nahrstedt, David Rodgers,   William H. Sanders, Tim Yardley
 *
 *      Information Trust Institute/Coordinated Science Laboratory
 * 
 *      University of Illinois
 *      
 *      The Board of Trustees of the University of Illinois
 *      109 Coble Hall
 *      801 South Wright Street
 *      Champaign, IL 61820-6242
 *
 *      http://www.iti.illinois.edu / http://csl.illinois.edu
 * 
 *      Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
 *      associated documentation files (the “Software”), to deal with the Software without restriction, 
 *      including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *      and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 *      subject to the following conditions:
 *
 *      Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *      following disclaimers.
 *      
 *      Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *      the following disclaimers in the documentation and/or other materials provided with the distribution.
 *
 *      Neither the names of Information Trust institute, Coordinated Science Laboratory, University of Illinois,
 *      The Board of Trustees of the University of Illinois nor the names of its contributors may be used to 
 *      endorse or promote products derived from this Software without specific prior written permission.
 *      
 *      THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 *      LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN
 *      NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *      WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 *      SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 *      
 \*****************************************************************************/
#endregion

#region [ Using ]
using GSF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using System.Threading.Tasks;
using SIEGate.Core;
using SIEGate.Core.Adapters;
using SIEGate.Core.Stats;
using SIEGate.Core.Fakes;
using SIEGate.Core.Notifications;
using SIEGate.Core.Measurements;
using SIEGate.Core.Measurements.Values;
using SIEGate.Core.Logging;
using SIEGate.Core.Legacy;
using SIEGate.Core.MessageBusses;
using GSF.TimeSeries.Transport;
#endregion

namespace SIEGateCoreTest
{
    /// <summary>
    /// Smart Adapter mock
    /// </summary>
    public class MockSmartAdapter : ISmartAdapter
    {
        #region [ Members ]
        private Dictionary<ISet<Guid>, ISet<Guid>> m_Map;
        #endregion

        #region [ Classes ]
        public class MockSmartAdapterInfo : ISmartAdapterInfo
        {
            #region [ Properties ]
            public Dictionary<ISet<Guid>, ISet<Guid>> Map
            {
                get;
                set;
            }
            #endregion 

            #region [ Constructor ]
            /// <summary>
            /// SmartAdapterInfo constructor
            /// </summary>
            /// <param name="incoming"></param>
            /// <param name="outgoing"></param>
            public MockSmartAdapterInfo(ISet<Guid> incoming, ISet<Guid> outgoing)
            {
                this.Map = new Dictionary<ISet<Guid>, ISet<Guid>>();
                IncomingStreamIDs = incoming;
                OutgoingStreamIDs = outgoing;
                RuntimeType = typeof(ISmartAdapter);
            }
            /// <summary>
            /// This constructor support smart adapter testing for various keys
            /// </summary>
            /// <param name="Map">Map of input/output ids for adapter as key/value pair</param>
            public MockSmartAdapterInfo(Dictionary<ISet<Guid>, ISet<Guid>> Map)
            {
                this.Map = Map;
                this.IncomingStreamIDs = new HashSet<Guid>();
                this.OutgoingStreamIDs = new HashSet<Guid>();
                foreach (KeyValuePair<ISet<Guid>, ISet<Guid>> pair in Map)
                {
                    foreach (ISet<Guid> key in Map.Keys)
                    {
                        IncomingStreamIDs.UnionWith(key);
                    }
                    foreach (ISet<Guid> value in Map.Values)
                    {
                        OutgoingStreamIDs.UnionWith(value);
                    }
                }

                RuntimeType = typeof(ISmartAdapter);
            }
            #endregion

            #region [ Methods ]
            public void SetStaticInputs(bool staticInputs)
            {
                this.StaticInputs = staticInputs;
            }

            public bool StaticInputs
            {
                get;
                set;
            }

            public int InitializationTimeout
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public event EventHandler<EventArgs<string>> Log;

            public void OnLog(string format, params object[] args)
            {
                throw new NotImplementedException();
            }

            public Dictionary<string, string> Settings
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public IAdapter MyInstance
            {
                get;
                set;
            }

            public ISet<Guid> IncomingStreamIDs
            {
                get;
                set;
            }

            public ISet<Guid> OutgoingStreamIDs
            {
                get;
                set;
            }

            public string Name
            {
                get;
                set;
            }

            public uint ID
            {
                get;
                set;
            }

            public Type RuntimeType
            {
                get;
                set;
            }

            public INotificationReceiver Receiver
            {
                get;
                set;
            }

            public void ExtractConfiguration(System.Data.DataSet configurationTables)
            {
                throw new NotImplementedException();
            }

            public void Update(Dictionary<string, string> configInfo)
            {
                throw new NotImplementedException();
            }
            #endregion
        }
        #endregion

        #region [ Constructor ]
        public MockSmartAdapter(ISmartAdapterInfo info)
        {
            m_Map = new Dictionary<ISet<Guid>, ISet<Guid>>();
            IncomingStreamIDs = info.IncomingStreamIDs;
            OutgoingStreamIDs = info.OutgoingStreamIDs;
            Info = info;
            ((ISmartAdapterInfo)Info).MyInstance = this;
        }
        public MockSmartAdapter(MockSmartAdapter.MockSmartAdapterInfo info)
        {
            m_Map = info.Map;
            IncomingStreamIDs = info.IncomingStreamIDs;
            OutgoingStreamIDs = info.OutgoingStreamIDs;
            Info = info;
            ((ISmartAdapterInfo)Info).MyInstance = this;
        } 
        #endregion

        #region [ Methods ]
        /// <summary>
        /// GetInputsFor returns last adapter incoming Guid
        /// Current Mock hardcoded to support AdapterContainer
        /// </summary>
        /// <param name="outputs"></param>
        /// <returns></returns>
        public ISet<Guid> GetInputsFor(ISet<Guid> outputs)
        {
            ISet<Guid> inputs = new HashSet<Guid>();
            if (m_Map.Count > 0)
            {
                foreach (Guid output in outputs)
                {
                    foreach (ISet<Guid> signals in m_Map.Where(item => item.Value.Contains(output)).Select(item => item.Key))
                    {
                        inputs.UnionWith(signals);
                    }
                }
            }
            else
            {
                foreach(Guid signal in outputs)
                {
                    inputs.Add(IncomingStreamIDs.Last());
                }
            }

            return inputs;
        }


        /// <summary>
        /// Handle changing inputs event
        /// </summary>
        public void OnChangeInputs()
        {
            if ((object)ChangeInputs != null)
                ChangeInputs(this, EventArgs.Empty);
        }

        public event EventHandler ChangeInputs;

        public MeasurementPasser Emit
        {
            get;
            set;
        }

        public ISet<Guid> IncomingStreamIDs
        {
            get;
            set;
        }

        public ISet<Guid> OutgoingStreamIDs
        {
            get;
            set;
        }

        public IAdapterInfo Info
        {
            get;
            set;
        }

        public void Collect(params IMeasurement[] input)
        {
            throw new NotImplementedException();
        }

        public void link(IAdapter next)
        {
            throw new NotImplementedException();
        }

        public uint ID
        {
            get { throw new NotImplementedException(); }
        }
        #endregion
    }
    
    /// <summary>
    /// Adapter mock
    /// </summary>
    public class MockAdapter : AdapterBase
    {

        #region [ Members ]
        private IMeasurement m_HandledMeasurement;
        #endregion 

        #region [ Classes ]
        public class MockAdapterInfo : AdapterBase.AdapterInfoBase
        {
            private Dictionary<string, string> m_defaults = new Dictionary<string, string>()
            {
                 {"foo","bar"},
                 {"erich", "heine"}
            };

            public MockAdapterInfo(ISet<Guid> incoming, ISet<Guid> outgoing)
            {
                SetDefaults(m_defaults);

                IncomingStreamIDs = incoming;
                OutgoingStreamIDs = outgoing;
                RuntimeType = typeof(AdapterBase);
            }

            public void SetMyInstance(IAdapter instance)
            {
                base.MyInstance = instance;
            }
        }
        #endregion

        #region [ Properties ]
        public IMeasurement HandledMeasurement
        {
            get 
            {
                return m_HandledMeasurement;
            }
        }
        public IMeasurement[] Measurements
        {
            get;
            set;
        }
        #endregion

        #region [ Constructor ]
        public MockAdapter(IAdapterInfo info)
            : base(info)
        {
            Emit = (IMeasurement[] m) => { Measurements = m; };
        }
        #endregion

        #region [ Methods ]
        protected override void HandleMeasurement(IMeasurement m)
        {
            m_HandledMeasurement = m;
        }
        #endregion
    }

    /// <summary>
    /// MockDataProcessorInfo represent mock for DataProcessorInfo
    /// </summary>
    public class MockDataProcessorInfo : ConfigInfo, IDataProcessorInfo
    {
        #region [ Methods ]
        public override Type RuntimeType
        {
            get;
            set;
        }
        public override void Update(Dictionary<string, string> configInfo)
        {
        }
        public override void ExtractConfiguration(System.Data.DataSet configurationTables)
        {
        }
        public MockDataProcessorInfo(ISet<Guid> incoming, ISet<Guid> outgoing)
        {
            IncomingStreamIDs = incoming;
            OutgoingStreamIDs = outgoing;
            RuntimeType = typeof(NetworkCommunicator);
        }
        #endregion
    }

    /// <summary>
    /// Measurement mock
    /// </summary>
    public class MockMeasurement : IMeasurement
    {
        #region [ Members ]
        private Guid streamID;
        private Ticks timestamp;
        private MeasurementStateFlags stateflags;
        private IMeasurementValue value;
        #endregion

        #region [ Constructors ]
        public MockMeasurement()
        {
            streamID = Guid.NewGuid();
            stateflags = MeasurementStateFlags.Normal;
            value = new DoubleValue(10);
            timestamp = new Ticks();
        }
        public MockMeasurement(Guid streamid)
        {
            streamID = streamid;
            stateflags = MeasurementStateFlags.Normal;
            value = new DoubleValue(10);
            timestamp = new Ticks();
        }
        #endregion

        #region [ Properties ]
        public Guid StreamID
        {
            get
            {
                return streamID;
            }
        }

        public Ticks Timestamp
        {
            get
            {
                return timestamp;
            }
        }

        public MeasurementStateFlags StateFlags
        {
            get
            {
                return stateflags;
            }
            set
            {
                new NotImplementedException();
            }
        }

        public IMeasurementValue Value
        {
            get
            {
                return value;
            }
        }
        #endregion

        #region [ Methods ]
        public IMeasurement Copy()
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    /// Supports AdapterContainerTests unit tests class
    /// </summary>
    public class MockMessageBusProxy : IMessageBusProxy
    {
        #region [ Members ]
        private IMeasurement[] measurements;
        private ISet<Guid> subscribed;
        private ISet<Guid> published;
        private ISet<Guid> activePubs;
        #endregion

        #region [ Constructor ]
        public MockMessageBusProxy()
        {
            // Initialize 
            subscribed = new SortedSet<Guid>();
            published = new SortedSet<Guid>();
            activePubs = new SortedSet<Guid>();
            MockMeasurement item = new MockMeasurement();
            List<MockMeasurement> items = new List<MockMeasurement>();
            items.Add(item);
            measurements = items.ToArray();

        }
        #endregion

        #region [ Methods ]
        /// <summary>
        /// Subscribed
        /// </summary>
        public ISet<Guid> Subscribed
        {
            get
            {
                return subscribed;
            }
        }

        /// <summary>
        /// Published
        /// </summary>
        public ISet<Guid> Published
        {
            get
            {
                return published;
            }
        }

        /// <summary>
        /// ActivePubs
        /// </summary>
        public ISet<Guid> ActivePubs
        {
            get
            {
                return activePubs;
            }
        }

        public void Subscribe(ISet<Guid> neededMessages)
        {
            foreach (Guid signal in neededMessages)
            {
                subscribed.Add(signal);
            }
        }

        public void TriggerSubscription(ISet<Guid> signals)
        {
            foreach (Guid signal in signals)
            {
                StartSubscription(this, new MessageBusSubscriptionEventArgs(signal));
            }
        }

        public void TriggerUnsubscription(ISet<Guid> signals)
        {
            foreach (Guid signal in signals)
            {
                EndSubscription(this, new MessageBusSubscriptionEventArgs(signal));
            }
        }

        /// <summary>
        /// Uses virtual producer
        /// </summary>
        /// <param name="providedMessages"></param>
        public void Publish(ISet<Guid> providedMessages)
        {
            foreach (Guid message in providedMessages)
            {
                published.Add(message);
            }
        }

        public void UnSubscribe(ISet<Guid> toRemove)
        {
            foreach (Guid signal in toRemove)
            {
                subscribed.Remove(signal);
            }
        }

        public void UnPublish(ISet<Guid> toRemove)
        {
            foreach (Guid signal in toRemove)
            {
                published.Remove(signal);
            }
        }

        public void Send(params IMeasurement[] m)
        {
            throw new NotImplementedException();
        }

        public IMeasurement[] Recv(int max = 0)
        {
            return measurements;
        }

        public event EventHandler<MessageBusSubscriptionEventArgs> StartSubscription;

        public event EventHandler<MessageBusSubscriptionEventArgs> EndSubscription;
        #endregion
    }

    /// <summary>
    /// INotificationReceiver mock 
    /// </summary>
    public class MockINotificationReceiver : INotificationReceiver
    {
        #region [ Members ]

        #endregion

        #region [ Constructors ]
        public MockINotificationReceiver()
        {
        }
        #endregion

        #region [ Methods ]
        public void RegisterBroadcastHandler(BroadcastNotification message, Action<IEnumerable<object>> handler)
        {
            throw new NotImplementedException();
        }

        public void RegisterTargetedHandler(string message, Action<IEnumerable<object>> handler)
        {
            //throw new NotImplementedException();
        }

        public void SendNotification(uint targetID, string message, params object[] arguments)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    /// Logger mock
    /// </summary>
    public class MockLogger : Logger
    {
        #region [ Members ]
        private int m_countCall = 0;
        #endregion

        #region [ Methods ]
        public override void Log(LogLevel level, DateTime time, string source, string tag, string message)
        {
            m_countCall++;
        }

        public int GetCountCall()
        {
            return m_countCall;
        }
        #endregion

    }

    /// <summary>
    /// A Mock for NetworkCommunicator class
    /// </summary>
    public class MockNetworkCommunicator : NetworkCommunicator
    {
        #region [ Properties ]
        /// <summary>
        /// m_statsCluster
        /// </summary>
        public Cluster StatsCluster
        {
            get
            {
                return base.m_statsCluster;
            }
        }
        #endregion

        #region [ Constructor ]
        /// <summary>
        /// MockNetworkCommunicator constructor
        /// </summary>
        /// <param name="busProxy">IMessageBusProxy</param>
        /// <param name="info">info</param>
        public MockNetworkCommunicator(IMessageBusProxy busProxy, NetworkCommunicatorInfoBase info) : base(busProxy,info)
        {
        }
        #endregion

        #region [ Methods ]
        public void StubUpdateBytesSent(int bytes)
        {
            base.UpdateBytesSent(bytes);
        }

        public void StubUpdateBytesReceived(int bytes)
        {
            base.UpdateBytesReceived(bytes);
        }

        public override void Start()
        {
            throw new NotImplementedException();
        }

        public override void Stop()
        {
            throw new NotImplementedException();
        }
        #endregion
    }


    /// <summary>
    /// A Mock for InputAdapter
    /// </summary>
    public class MockInputAdapter : InputAdapter
    {
        #region [ Constructor ]
        public MockInputAdapter(IAdapterInfo conf)
            : base(conf)
        { }
        #endregion

        #region [ Methods ]
        protected override void HandleMeasurement(IMeasurement m)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    /// A Mock for ActionAdapter
    /// </summary>
    public class MockActionAdapter : ActionAdapter
    {
        #region [ Constructor ]
        public MockActionAdapter(IAdapterInfo conf)
            : base(conf)
        { }
        #endregion

        #region [ Methods ]
        protected override void HandleMeasurement(IMeasurement m)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    /// A Mock for OutputAdapter
    /// </summary>
    public class MockOutputAdapter : OutputAdapter
    {
        #region [ Constructor ]
        public MockOutputAdapter(IAdapterInfo conf)
            : base(conf)
        { }
        #endregion

        #region [ Methods ]
        protected override void HandleMeasurement(IMeasurement m)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}
